﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Net;
using AMIUtilities;
using System.Collections;

//    Copyright (C) 2011 Officebroker.com LTD.
//    Neil Cadman, Alex Welding, Andrew Coombs, Jan Rygielski
//    Sir Robert Peel Mill, Mill Lane, Staffordshire, Fazely, B78 3QD, England
//
//    This file is part of AMIProxy Project.
//
//    AMIProxy Project is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    AMIProxy Project is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License (GNU AGPL)
//    along with AMIProxy Project.  If not, see <http://www.gnu.org/licenses/>.

namespace PhoneStateLogic
{
    public class PhoneState
    {
        // Private Variables
        private TcpClient _tcpClient;
        private ManagedSocket _managedSocket;
        private PhoneChangedDelegate _phoneChanged;
        private PhoneChangedDelegate _phoneAdded;

        private String command = "";

        private const String ENDLINEORNOTHING = "(|$)";
        private const String ANYTHINGANDSPACES = "([ \\S ]*)";
        private const String STATEDESCPATTERN = "(StatusDesc: )" + ANYTHINGANDSPACES + ENDLINEORNOTHING;
        private const String EXTENSIONPATTERN = "(Extension: )" + ANYTHINGANDSPACES + ENDLINEORNOTHING;
        private const String ACTIONPATTERN = "(Action: )" + ANYTHINGANDSPACES + ENDLINEORNOTHING;

        // Public Enums
        public enum State
        {
            Free,
            Recieving,
            Busy
        }

        // Public Delegates
        public delegate void PhoneChangedDelegate(String message, State type);

        // Private Delegates
        private delegate void readSocketDelegate(Socket socket);

        // Public Events
        public event PhoneChangedDelegate PhoneChanged
        {
            add { _phoneChanged += value; }
            remove { _phoneChanged -= value; }
        }
        public event PhoneChangedDelegate PhoneAdded
        {
            add { _phoneAdded += value; }
            remove { _phoneAdded -= value; }
        }
        
        // Public Methods
        public void InitiateConnection(String hostName, Int32 port)
        {
            _tcpClient = new TcpClient(hostName, port);

            _managedSocket = new ManagedSocket(RandomFactory.Create().Next(1000000).ToString(), _tcpClient.Client);
            _managedSocket.DataReceived += new ManagedSocket.dataReceivedDelegate(_managedSocket_DataReceived);
            _managedSocket.ReadStart();
        }

        public void ShutDown()
        {
            if (_managedSocket != null)
                _managedSocket.Close();

            if (_tcpClient != null)
                _tcpClient.Close();
        }
        public virtual void newMessage(String message)
        { }
        public void SendMessageToAMI(String message)
        {
            _managedSocket.SendMessage(message);
        }

        // Private Methods
        private void HandleMessage(String message)
        {
            if (Regex.Match(message, "(PhoneStateNew)").Success) 
                NewPhoneMessage(message, Regex.Match(message, "(PhoneStateNew)").Result("$1"));
            else if (Regex.Match(message, "(PhoneStateUpdate)").Success)
                NewPhoneMessage(message, Regex.Match(message, "(PhoneStateUpdate)").Result("$1"));

            newMessage(message);
        }
        private void NewPhoneMessage(String message, String type)
        {
            String Extension;
            String State;

            Extension = Regex.Match(message, "(Extension: )(.+)(,)").Result("$2");
            State = Regex.Match(message, "(State: )(.+)").Result("$2");

            OnPhoneChanged(Extension, (State)Enum.Parse(typeof(State), State));
        }

        private void OnPhoneChanged(String extension, State state)
        {
            if (_phoneChanged != null)
                _phoneChanged.RaiseEventSafely(new Object[] { extension, state });
        }
        
        private void _managedSocket_DataReceived(ManagedSocket socket, Byte[] data)
        {
            String[] lines;

            command += Encoding.ASCII.GetString(data, 0, data.Length);

            lines = Regex.Split(command, "\\r\\n\\r\\n", RegexOptions.Multiline);

            for (Int32 i = 0; i < lines.Length - 1; i++)
            {
                HandleMessage(lines[i]);
            }

            command = lines[lines.Length - 1];
        }
    }
}
